<?php

namespace PhpYes\Apps;

use PhpYes\Com\ExtName;

/**
 * 通用说明:
 *
 * 1. 本类中 没有使用 final 修饰的 public 和 protected 成员方法 都是 子类可以重写的.
 *
 */
abstract class BaseConfigApp extends BaseAppBase
{
    // 应用层 可能会有一个 ConfigApp

    protected $_config;

    /**
     * config 设计(规划) :
     * config(file) : 获取配置文件 file 的内容，!!! 通用版本，处于 env 下的配置文件也能获取到 且 优先级更高，
     * 即先尝试获取处于 env 下的配置文件，如果获取不到再尝试获取处于 config_dir 下的配置文件
     * config_spec(file) : 获取处于 config_dir 下的配置文件 file 的内容，!!! 简单高效版本，只会获取处于 config_dir 下的配置文件
     *
     * 获取配置 name 的 配置文件名 : config_${name}_file(), 例如获取配置 route 的 配置文件名 config_route_file()
     * 获取配置 name 的 配置内容 : config_${name}(), 例如获取配置 route 的 配置内容 config_route()
     *
     * 特殊情况处理 :
     * 按照设计，获取配置 config 的 配置文件名应该是 config_config_file, 这个函数名字太长了而且容易让人下意识的怀疑是否拼写错了，
     * 所以我们决定特殊处理一下这个，将 config_config_file() 改成 config_file(), config_config() 保持不变
     *
     * 总结 :
     * config_dir() : 获取 config 目录，不是获取配置 dir 的 配置内容，不存在名为 dir 的配置
     * config(file) : 获取配置文件 file 的内容，!!! 通用版本
     * config_spec(file) : 获取处于 config_dir 下的配置文件 file 的内容，!!! 简单高效版本，不是获取配置 spec 的 配置内容，不存在名为 spec 的配置
     * config_file() : 获取配置 config 的 配置文件名
     * config_config() : 获取配置 config 的 配置内容
     * config_route_file() : 获取配置 route 的 配置文件名
     * config_route() : 获取配置 route 的 配置内容
     * ...
     */

    /**
     * 支持 php 和 json
     * @param string $file
     * @return mixed|null
     */
    public function config_spec($file)
    {
        $file = empty($file) ? null : trim($file);
        if (empty($file)) {
            return null;
        }
        if ($this->_config && isset($this->_config[$file])) {
            return $this->_config[$file];
        }

        $file_path = $this->config_dir() . '/' . $file;
        if (!is_file($file_path)) {
            return null;
        }
        if (empty($this->_config)) {
            $this->_config = [];
        }

        $ext = ExtName::dot_ext($file);
        $ext = empty($ext) ? '' : strtolower($ext);
        if ($ext == '.php') {
            $this->_config[$file] = require $file_path;
        } elseif ($ext == '.json') {
            $str = file_get_contents($file_path);
            $str = empty($str) ? '' : trim($str);
            $json = null;
            if ($str) {
                $json = @json_decode($str, true);
            }
            $this->_config[$file] = empty($json) ? [] : $json;
        } else {
            $str = file_get_contents($file_path);
            $str = empty($str) ? '' : trim($str);
            $this->_config[$file] = $str;
        }

        return $this->_config[$file];
    }

    /**
     * @return string[]
     */
    public function config_spec_files()
    {
        return [$this->config_file()];
    }

    /**
     * 支持 php 和 json
     * @param string $file
     * @return mixed|null
     */
    public function config($file)
    {
        $file = empty($file) ? null : trim($file);
        if (empty($file)) {
            return $this->_config;
        }
        if ($this->_config && isset($this->_config[$file])) {
            return $this->_config[$file];
        }

        if ($file == $this->config_file() || in_array($file, $this->config_spec_files())) {
            return $this->config_spec($file);
        }

        $config_dir = $this->config_dir();

        $file_path = $config_dir . '/' . $this->env() . '/' . $file;
        if (!is_file($file_path)) {
            $file_path = $config_dir . '/' . $file;
            if (!is_file($file_path)) {
                return null;
            }
        }
        if (empty($this->_config)) {
            $this->_config = [];
        }

        $ext = ExtName::dot_ext($file);
        $ext = empty($ext) ? '' : strtolower($ext);
        if ($ext == '.php') {
            $this->_config[$file] = require $file_path;
        } elseif ($ext == '.json') {
            $str = file_get_contents($file_path);
            $str = empty($str) ? '' : trim($str);
            $json = null;
            if ($str) {
                $json = @json_decode($str, true);
            }
            $this->_config[$file] = empty($json) ? [] : $json;
        } else {
            $str = file_get_contents($file_path);
            $str = empty($str) ? '' : trim($str);
            $this->_config[$file] = $str;
        }

        return $this->_config[$file];
    }

    /**
     * @return string
     */
    public function config_file()
    {
        return 'config.php';
    }

    /**
     * @return array|null
     */
    public function config_config()
    {
        return $this->config_spec($this->config_file());
    }

    /**
     * @return string
     */
    public function env()
    {
        $config = $this->config_config();
        return empty($config['env']) ? self::ENV_PRODUCTION : $config['env'];
    }
}